/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package FEMSolver;

import BounderyPack.DBoundery;
import BounderyPack.DirihletPair;
import HashMatrix2.HashMatrix2;
import HashMatrix2.LUFactorization;
import MathLib.triangulation.SaveStructures.Node;

import java.io.BufferedOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author mark_o
 */
public class overRelaxsationProjectionMethod {
    protected ArrayList<DBoundery> NodeList;
    public ArrayList<Node> BoundsNodeList;
    public OutputStream outPath;
    DirihletPair [] mas;
    HashMatrix2 A;
    ArrayList<Double> C;
    double[] b;
    double w;
    double eps;

    public overRelaxsationProjectionMethod(ArrayList<DBoundery> NodeList, OutputStream outPath, DirihletPair[] mas, HashMatrix2 A, ArrayList<Double> C, double[] b, double w, double eps) {
        this.NodeList = NodeList;
        this.outPath = outPath;
        this.mas = mas;
        this.A = A;
        this.C = C;
        this.b = b;
        this.w = w;
        this.eps = eps;
    }
    
    private boolean check(double[] prev, double[] next){
        boolean key = true;
        for(int i=0;i<prev.length;i++){
            if(Math.abs(prev[i]-next[i])>eps){
                key = false;
                System.out.print("перевірка:\t");
                System.out.println(i+"\t"+Math.abs(prev[i]-next[i]));
                break;
            }
        }
        return key;
    }
    
    
    public void calc(){
        // перше наближення
        LUFactorization lu = new LUFactorization(A);
        double[] u0 = lu.calculate(b);
        for (int i = 0; i < u0.length; i++) {
			u0[i] = 0;
		}
        
        while (true) {
            double[] u1 = new double[u0.length];
            double[] uTmp = new double[u0.length];
            for (int i = 0; i < uTmp.length; i++) {
                ArrayList<Double> valList = A.getJRowValues(i);
                ArrayList<Integer> posList = A.getJRowIndex(i);
                double sum1 = 0.0;
                    int pos = 0;
                    while(posList.get(pos)<i-1){
                        sum1+=valList.get(pos)*uTmp[posList.get(pos)];
                        pos++;
                    }
                double sum2 = 0.0;
                    while(pos<posList.size()){
                        sum2+=valList.get(pos)*u0[posList.get(pos)];
                        pos++;
                    }

                uTmp[i] = ( b[i] - sum1 - sum2 )/A.getValue(i, i);
                u1[i]=P(i,(  u0[i] + w*( uTmp[i]-u0[i] ) ));

            }

            
            if (check(u0, u1)) {
                u0=u1;
                break;
            }
            u0=u1;
        }
        System.out.println("розвязок\n===================================================================");
        //for(int i=0;i<b.length;i++){
        //    System.out.println((u0[i]));
        //}

        //print result to file

        PrintWriter pw =  null;
        try {
            pw = new PrintWriter(new BufferedOutputStream((outPath)));
            pw.println(u0.length + mas.length);
        if(mas.length>0){
            int j;
            for (j = 0; j < mas[0].getNodeNumber(); j++) {
                pw.println(u0[j]);
            }

            for(int i=0; i<mas.length-1; i++){
                int k=0;
                pw.println(mas[i].getValue());
                while(mas[i+1].getNodeNumber() - mas[i].getNodeNumber()-k!=1){
                    pw.println(u0[j]);
                    j++;
                    k++;
                }
            }

            pw.println(mas[mas.length-1].getValue());

            for (int i = j; i < u0.length; i++) {
                pw.println(u0[i]);
            }
        }else{
            for (int i = 0; i < u0.length; i++) {
                pw.println(u0[i]);
            }
        }

        } catch (Exception ex) {
            Logger.getLogger(MyPenaltyIteration.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            pw.close();
        }






        
    }

    private double P(int i,double d) {
//        for (int j = 0; j < NodeList.size(); j++) {
//            DBoundery boundery = NodeList.get(j);
//            if(boundery.contains(i)){
//                return Math.max(C.get(i), d);////////////////////////////////////////////////////////////////
//            }
//        }
    	for (int j = 0; j < BoundsNodeList.size(); j++) {
			if(BoundsNodeList.get(j).Number==i){
				return Math.max(0, d);
			}
		}
        return d;
        
    }



}
